using System;
using System.IO;
using System.Linq;
using System.Text;
using Prjinit.Helpers;
using Prjinit.Vcses;
using XenoGears;
using XenoGears.Reflection.Attributes;
using XenoGears.Assertions;
using XenoGears.Functional;
using XenoGears.Streams;

namespace Prjinit.Templates.Core
{
    internal abstract class ExtractAndMacroExpandTemplate : Template
    {
        protected abstract String MacroExpand(String s);

        public override void Bootstrap()
        {
            var t_name = this.GetType().Attr<TemplateAttribute>().Aliases.AssertFirst();
            Debug.EnsureBlankLine();
            Debug.WriteLine("Bootstrapping template \"{0}\"...", t_name);

            var asm = this.GetType().Assembly;
            var resources_ns = this.GetType().FullName.Substring(0, this.GetType().FullName.Length - "Template".Length);
            resources_ns = resources_ns.Substring(asm.GetName().Name.Length + 1);
            var resources_path = resources_ns.Replace(".", Path.DirectorySeparatorChar.ToString());

            var res_files = ProjectFiles.EmbeddedResources.Where(s => s.StartsWith(resources_path))
                .Select(s => s.Substring(resources_path.Length + 1)).ToReadOnly();
            Debug.WriteLine("Found {0} relevant files embedded into resources at: {1}.", res_files.Count(), resources_path);

            foreach (var res_file in res_files)
            {
                var file = new FileInfo(MacroExpand(Path.Combine(Cfg.TargetDir.FullName, res_file)));
                if (!Directory.Exists(file.DirectoryName)) Directory.CreateDirectory(file.DirectoryName);
                Debug.WriteLine("Extracting {0} to: {1}...", res_file, file.FullName);

                var res_name = asm.GetName().Name + "." + resources_ns + "." + res_file.Replace(Path.DirectorySeparatorChar.ToString(), ".");
                res_name = asm.GetManifestResourceNames().Single(name => name.Replace("%", "_").Replace("$", "_") == res_name.Replace("%", "_").Replace("$", "_"));
                using (var s_res = asm.GetManifestResourceStream(res_name)) s_res.DumpToFile(file.FullName);
                Debug.WriteLine("Successfully extracted {0} to: {1}.", res_file, file.FullName);

                if (file.IsText())
                {
                    Debug.WriteLine("Macroexpanding {0}...", file.FullName);
                    var text = File.ReadAllText(file.FullName, Encoding.UTF8);
                    text = MacroExpand(text);
                    File.WriteAllText(file.FullName, text, Encoding.UTF8);
                    Debug.WriteLine("Successfully macroexpanded {0}.", file.FullName);
                }
            }

            // todo. implement this in less ad-hoc way
            if (!(Cfg.Vcs is Mercurial))
            {
                var hgignores = Cfg.TargetDir.GetFiles(".hgignore", SearchOption.AllDirectories);
                if (hgignores.IsNotEmpty() && Cfg.IsVerbose) Debug.EnsureBlankLine();
                hgignores.ForEach(f =>
                {
                    Debug.WriteLine("Deleting {0}...", f.FullName);
                    f.Delete();
                    Debug.WriteLine("Successfully deleted {0}.", f.FullName);
                });
            }
        }
    }
}